package cn.itcast.nems.base.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.itcast.ic.common.exception.v2.BizExceptionProducer;
import cn.itcast.nems.base.api.ClazzApi;
import cn.itcast.nems.base.dto.ClazzDTO;
import cn.itcast.nems.base.dto.DiscountQueryDTO;
import cn.itcast.nems.base.dto.DiscountTotalDTO;
import cn.itcast.nems.base.service.DiscountsQueryService;
import cn.itcast.nems.base.util.DiscountUtil;
import cn.itcast.nems.common.constant.DiscountTypeEnum;
import cn.itcast.nems.common.enumeration.NemsErrorBodyEnum;
import cn.itcast.nems.common.util.LocalDateTimeUtils;
import cn.itcast.nems.common.util.NumberUtil;
import cn.itcast.nems.discount.api.DiscountApi;
import cn.itcast.nems.discount.dto.DiscountSummaryDTO;
import cn.itcast.nems.discounts.dao.dataobject.EmsDiscountsDO;
import cn.itcast.nems.discounts.dao.mapper.EmsDiscountsMapper;
import cn.itcast.nems.order.api.JournalDiscountApi;
import cn.itcast.nems.order.dto.JournalDiscountApiReqDTO;
import cn.itcast.nems.order.dto.JournalDiscountApiResDTO;
import cn.itcast.nems.product.scheduler.TuitionFeeService;
import cn.itcast.nems.studentrecord.service.DiscountCalculator;
import com.alibaba.fastjson.JSON;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Service
@RequiredArgsConstructor
@Slf4j
public class DiscountsQueryServiceImpl implements DiscountsQueryService {
    private final EmsDiscountsMapper emsDiscountsMapper;
    private final JournalDiscountApi journalDiscountApi ;
    private final TuitionFeeService tuitionFeeService ;
    private final DiscountApi discountApi;
    private final ClazzApi clazzApi;

    @Override
    public DiscountTotalDTO findChildListAndCalculateDiscountAmount(@NonNull DiscountQueryDTO discountQueryDTO)
    {
        Assert.notNull(discountQueryDTO.getClazzId(), BizExceptionProducer.produce(NemsErrorBodyEnum.PARAM_EMPTY, "班级ID"));
        DiscountTotalDTO totalDTO = new DiscountTotalDTO();
        EmsDiscountsDO discountsDO = this.wrapDiscountDO(discountQueryDTO.getClazzId());
        discountsDO.setRealationDiscountsId(discountQueryDTO.getParentId());
        List<EmsDiscountsDO> list = Objects.nonNull(discountQueryDTO.getParentId()) ?
                emsDiscountsMapper.findByParentIdByClazzId(discountsDO) :
                emsDiscountsMapper.getDiscountsByCondition(discountsDO);
        log.info("[根据班级ID查询优惠项] 班级ID：{}, 查询结果：{}" ,discountQueryDTO.getClazzId() , JSON.toJSONString(list));
        final BigDecimal tuitionFee = tuitionFeeService.findTuition(discountQueryDTO.getClazzId() ,null) ;
        log.info("[根据班级ID查询优惠项] 班级ID：{}, 查询价格：{}" ,discountQueryDTO.getClazzId() ,tuitionFee);

        List<DiscountSummaryDTO> summaryList = new ArrayList<>();
        // 普通优惠
        if (CollectionUtil.isNotEmpty(discountQueryDTO.getIds())) {
            summaryList.addAll( discountQueryDTO.getIds().stream().map(discountApi::getSummaryById).toList()) ;
        }
        // 个人优惠
        if (CollectionUtil.isNotEmpty(discountQueryDTO.getDiscountCouponIds())) {
            summaryList.addAll(this.queryCouponDiscount(discountQueryDTO.getDiscountCouponIds()));
        }
        DiscountCalculator discountCalculator =  new DiscountCalculator(summaryList) ;
        // 班级执行价格
        int clazzPrice = tuitionFee.multiply(BigDecimal.valueOf(100)).intValue();
        int discountAmount = discountCalculator.calculate(clazzPrice, clazzPrice) ;
        totalDTO.setDiscountAmount(NumberUtil.convertToYuan(discountAmount).toString());
        int remainMoney = CollectionUtil.isNotEmpty(summaryList) ? clazzPrice - discountAmount :clazzPrice;
        totalDTO.setRemainMoney(NumberUtil.convertToYuan(remainMoney).toString());
        // 级联普通优惠列表
        totalDTO.setSelectList( CollectionUtil.isEmpty(list) ? null :
                list.stream().map(item -> DiscountUtil.transferDiscountDTO(item, tuitionFee,remainMoney)).toList());
        // 已选的优惠列表 ， 普通优惠 +  个人优惠
        totalDTO.setList(DiscountUtil.getDiscountList(discountCalculator,summaryList));
        log.info("【[根据班级ID查询优惠项]】查询结果：{}" , JSON.toJSONString(totalDTO));
        return totalDTO;
    }

    @Override
    public List<DiscountSummaryDTO> queryCouponDiscount(List<String> couponList) {
        List<DiscountSummaryDTO> list = new ArrayList<>() ;
        for (int i = 0; i < couponList.size(); i++) {
            list.add(this.covertToSummaryDTO(journalDiscountApi.queryByLineId(JournalDiscountApiReqDTO.buildForQueryByLineId(couponList.get(i))))) ;
        }
        return list;
    }


    /**
     * <p>
     *  将 JournalDiscountApiResDTO 转化为 DiscountSummaryDTO
     * </p>
     *
     * @author zhouwei
     * @since 2023/12/13 5:16 PM
     **/
    private DiscountSummaryDTO covertToSummaryDTO(@NonNull JournalDiscountApiResDTO apiResDTO) {
        DiscountSummaryDTO summaryDTO = new DiscountSummaryDTO();
        summaryDTO.setId(Integer.valueOf(apiResDTO.getDiscountId()));
        summaryDTO.setName(apiResDTO.getDiscountName());
        if(DiscountTypeEnum.DISCOUNT.name().equalsIgnoreCase(apiResDTO.getDiscountType())) {
            summaryDTO.setType(1);
            summaryDTO.setRate(apiResDTO.getDiscountValue().doubleValue());
        }else  {
            summaryDTO.setType(0);
            summaryDTO.setAmount(apiResDTO.getDiscountValue());
        }
        return summaryDTO  ;
    }

    private EmsDiscountsDO wrapDiscountDO(Integer clazzId) {
        ClazzDTO clazzDO  = clazzApi.queryByClassId(clazzId) ;
        Assert.notNull(clazzDO , BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "班级ID："+ clazzId)) ;
        EmsDiscountsDO discountsDO  =new EmsDiscountsDO() ;
        discountsDO.setClasstypeId(clazzDO.getClassTypeId());
        discountsDO.setSchoolId(clazzDO.getSchoolId());
        discountsDO.setSubjectId(clazzDO.getSubjectId());
        discountsDO.setClazzDate(LocalDateTimeUtils.formatLocalDate(clazzDO.getStartDate()));
        discountsDO.setFeeDate(DateUtil.formatDate(new Date()));
        return  discountsDO ;
    }

}
